home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 526-550 / disk_534 / term / libs.lzh / XprXModem / dlink.c < prev    next >
C/C++ Source or Header  |  1991-07-26  |  12KB  |  491 lines

  1. /* dlink - data link transfer routines for bmodem */
  2.  
  3. /*
  4.  * by David Betz, BYTE Magazine/BIX
  5.  * 
  6.  * statements involving bm_infoinit(), bm_info() added by Willy Langeveld for
  7.  * VLT
  8.  * 
  9.  * ANSIsized and made re-entrant by Marc Boucher for XPR implementation.
  10.  * 
  11.  */
  12.  
  13. #include <string.h>
  14. #include <stdio.h>
  15.  
  16. #include "xprxmodem.h"
  17.  
  18. #include "proto-dlink.h"
  19. #include "proto-xprxmodem.h"
  20. #include "proto-callback.h"
  21.  
  22. /* useful definitions */
  23. #define TRUE    1
  24. #define FALSE   0
  25.  
  26. /* protocol characters */
  27. #define SOH     0x01        /* start of a 128 byte block */
  28. #define STX     0x02        /* start of a 1024 byte block */
  29. #define EOT     0x04        /* end of a complete file */
  30. #define ACK     0x06        /* positive acknowledgement */
  31. #define NAK     0x15        /* negative acknowledgement */
  32. #define CAN     0x18        /* cancel transfer */
  33. #define CRC     'C'        /* CRC request (instead of NAK to start a
  34.                  * transfer) */
  35.  
  36. /* routine status codes */
  37. #define DT_EOF  -1
  38. #define DT_OK   1
  39.  
  40. /* number of times to retry */
  41. #define RETRY   10
  42.  
  43. /* timeout loop counters */
  44. #define STIME   4        /* timeout between characters of a packet */
  45. #define LTIME   20        /* timeout waiting for an ACK/NAK */
  46. #define XTIME   60        /* timeout waiting for initial NAK */
  47.  
  48. /* dlabort - wait for the line to clear */
  49. static void dlabort(struct XPR_IO * IO)
  50. {
  51.     int res;
  52.  
  53.     do
  54.         res = md_get(IO, STIME);
  55.     while ((res != DT_TIME) && (res != DT_ERR));
  56. }
  57.  
  58. /* chk_compute - compute the checksum */
  59. static int chk_compute(unsigned char *buf, int len)
  60. {
  61.     int chk, i;
  62.  
  63.     for (chk = i = 0; i < len; ++i)
  64.         chk += buf[i];
  65.     return (chk & 0xFF);
  66. }
  67.  
  68. /* crc_compute - compute the CRC value */
  69. static int crc_compute(unsigned char *buf, int len)
  70. {
  71.     int crc, shifter, highbit, i;
  72.  
  73.     buf[len++] = '\0';
  74.     buf[len++] = '\0';
  75.     for (crc = i = 0; i < len; ++i)
  76.         for (shifter = 0x80; shifter; shifter >>= 1) {
  77.             highbit = crc & 0x8000;
  78.             crc <<= 1;
  79.             crc |= (buf[i] & shifter ? 1 : 0);
  80.             if (highbit)
  81.                 crc ^= 0x1021;
  82.         }
  83.     return (crc & 0xFFFF);
  84. }
  85.  
  86. static char *blkchk[] =
  87. {"Checksum", "CRC-16"};
  88. static char *timefmt = "%02ld:%02ld:%02ld";
  89.  
  90. static void bm_info(struct XPR_IO * IO, int error)
  91. {
  92.     long (*xupdate) (), (*xchkmisc) (void);
  93.     struct XPR_UPDATE xpru;
  94.     long secs, micros, elapsed;
  95.     char buff1[20], buff2[20];
  96.     int blksiz, Iblknum;
  97.  
  98.     blksiz=IO->xpr_data->msglength;
  99.     Iblknum=IO->xpr_data->blknum;
  100.  
  101.     xchkmisc = IO->xpr_chkmisc;
  102.  
  103.     if (xchkmisc)
  104.         xchkmisc();
  105.  
  106.     /*
  107.      * Calculate elapsed time in tenths of seconds
  108.      */
  109.     CurrentTime(&secs, µs);
  110.     secs -= IO->xpr_data->startsecs;
  111.     micros -= IO->xpr_data->startmics;
  112.     elapsed = (secs * 10L) + (micros / 100000L);
  113.  
  114.     /*
  115.      * Always update data rate and elapsed time
  116.      */
  117.     xpru.xpru_updatemask = XPRU_DATARATE | XPRU_ELAPSEDTIME;
  118.  
  119.     sprintf(buff1, timefmt, secs / 3600L, (secs / 60L) % 60L, secs % 60L);
  120.     xpru.xpru_elapsedtime = buff1;
  121.  
  122.     if (elapsed)
  123.         xpru.xpru_datarate = ((long) blksiz * Iblknum * 10L) / elapsed;
  124.     else
  125.         xpru.xpru_datarate = 0;
  126.  
  127.     /*
  128.      * If we know the file size and the data rate we can compute the
  129.      * estimated time.
  130.      */
  131.     if (IO->xpr_data->filsiz) {
  132.         if (xpru.xpru_datarate) {
  133.             xpru.xpru_updatemask |= XPRU_EXPECTTIME;
  134.             secs = IO->xpr_data->filsiz / xpru.xpru_datarate;
  135.             sprintf(buff2, timefmt, secs / 3600L, (secs / 60L) % 60L, secs % 60L);
  136.             xpru.xpru_expecttime = buff2;
  137.         }
  138.     }
  139.  
  140.     /*
  141.      * On error, timeout or otherwise, update different things
  142.      */
  143.     if (error == DT_ERR) {
  144.         IO->xpr_data->numerrs++;
  145.         xpru.xpru_updatemask |= XPRU_ERRORS;
  146.         xpru.xpru_errors = IO->xpr_data->numerrs;
  147.     } else if (error == DT_TIME) {
  148.         IO->xpr_data->numtime++;
  149.         xpru.xpru_updatemask |= XPRU_TIMEOUTS;
  150.         xpru.xpru_timeouts = IO->xpr_data->numtime;
  151.     } else {
  152.         xpru.xpru_updatemask |= XPRU_BLOCKS | XPRU_BLOCKSIZE |
  153.             XPRU_BLOCKCHECK | XPRU_BYTES;
  154.         xpru.xpru_blocks = (long) Iblknum;
  155.         xpru.xpru_blocksize = (long) blksiz;
  156.         xpru.xpru_bytes = (long) blksiz *(long) Iblknum;
  157.  
  158.         xpru.xpru_blockcheck = IO->xpr_data->crcmode ? blkchk[1] : blkchk[0];
  159.     }
  160.  
  161.     /*
  162.      * Do the actual update
  163.      */
  164.     if ((xupdate = IO->xpr_update) != NULL)
  165.         calla(xupdate, &xpru);
  166.  
  167.     return;
  168. }
  169.  
  170. /* mdsnd - send a buffer of data */
  171. static int mdsnd(struct XPR_IO * IO)
  172. {
  173.     int plength, retries, ch;
  174.  
  175.     /* setup the packet header */
  176.     IO->xpr_data->packet[0] = IO->xpr_data->msgstart;
  177.     IO->xpr_data->packet[1] = IO->xpr_data->blknum;
  178.     IO->xpr_data->packet[2] = ~IO->xpr_data->blknum;
  179.  
  180.     /* compute the block check code */
  181.     if (IO->xpr_data->crcmode) {    /* compute the CRC */
  182.         long dumb_index;/* workaround manx expression too complex bug */
  183.  
  184.         IO->xpr_data->chksum = crc_compute(IO->xpr_data->buffer, IO->xpr_data->msglength);
  185.         IO->xpr_data->buffer[IO->xpr_data->msglength] = IO->xpr_data->chksum >> 8;
  186.         dumb_index = IO->xpr_data->msglength + 1;
  187.         IO->xpr_data->buffer[dumb_index] = IO->xpr_data->chksum;
  188.         plength = IO->xpr_data->msglength + 5;
  189.     } else {        /* compute the checksum */
  190.         long dumb_index;/* workaround manx expression too complex bug */
  191.  
  192.         IO->xpr_data->chksum = chk_compute(IO->xpr_data->buffer, IO->xpr_data->msglength);
  193.         dumb_index = IO->xpr_data->msglength;
  194.         IO->xpr_data->buffer[dumb_index] = IO->xpr_data->chksum;
  195.         plength = IO->xpr_data->msglength + 4;
  196.     }
  197.  
  198.     /* send data and wait for an ACK */
  199.     for (retries = 0; retries < RETRY; retries++) {
  200.  
  201.         /* send the data */
  202.         md_write(IO, IO->xpr_data->packet, plength);
  203.  
  204.         /* return on an ACK */
  205.         if ((ch = md_get(IO, LTIME)) == ACK)
  206.             return (DT_OK);
  207.  
  208.         /* abort transfer on two successive CAN's */
  209.         else if (ch == CAN) {
  210.             if ((ch = md_get(IO, STIME)) == ACK)
  211.                 return (DT_OK);
  212.             else if (ch == CAN)
  213.                 break;
  214.         } else if (ch == DT_ERR) {
  215.             dlabort(IO);
  216.             md_put(IO, CAN);
  217.             md_put(IO, CAN);
  218.             return (DT_ERR);
  219.         }
  220.         bm_info(IO, ch);
  221.     }
  222.  
  223.     /* return failure */
  224.     return (DT_ERR);
  225. }
  226.  
  227. /* msgput - put a message data character */
  228. static int msgput(struct XPR_IO * IO, int ch)
  229. {
  230.     int sts;
  231.  
  232.     IO->xpr_data->buffer[IO->xpr_data->bufptr++] = ch;
  233.     if (IO->xpr_data->bufptr == IO->xpr_data->msglength) {
  234.         bm_info(IO, 0);
  235.         if ((sts = mdsnd(IO)) != DT_OK)
  236.             return (sts);
  237.         ++IO->xpr_data->blknum;
  238.         IO->xpr_data->bufptr = 0;
  239.     }
  240.     return (ch);
  241. }
  242.  
  243. /* mdrcv - receive a buffer of data */
  244. static int mdrcv(struct XPR_IO * IO)
  245. {
  246.     int plength, i, ch, retries;
  247.  
  248.     /* receive data */
  249.     for (retries = 0; retries < RETRY + 1; retries++) {
  250.  
  251.         /* check for data packet or eot */
  252.         if ((ch = md_get(IO, LTIME)) == DT_TIME) {
  253.             bm_info(IO, ch);
  254.             md_put(IO, IO->xpr_data->nak);
  255.             continue;
  256.         } else if (ch == DT_ERR) {
  257.             bm_info(IO, ch);
  258.             dlabort(IO);
  259.             md_put(IO, CAN);
  260.             md_put(IO, CAN);
  261.             return (DT_ERR);
  262.         } else if (ch == EOT) {    /* end of transfer */
  263.             md_put(IO, ACK);
  264.             return (DT_EOF);
  265.         } else if (ch == SOH)    /* start of a short packet */
  266.             IO->xpr_data->msglength = SMSGLEN;
  267.         else if (ch == STX)    /* start of a long packet */
  268.             IO->xpr_data->msglength = LMSGLEN;
  269.         else {
  270.             bm_info(IO, DT_ERR);
  271.             dlabort(IO);
  272.             md_put(IO, IO->xpr_data->nak);
  273.             continue;
  274.         }
  275.  
  276.         /* reset the NAK character */
  277.         IO->xpr_data->nak = NAK;
  278.  
  279.         /* compute the packet length */
  280.         plength = IO->xpr_data->msglength + (IO->xpr_data->crcmode ? 5 : 4);
  281.  
  282.         /* receive the data */
  283.         for (i = 1; i < plength; IO->xpr_data->packet[i++] = ch) {
  284.             if ((ch = md_get(IO, STIME)) == DT_TIME)
  285.                 break;
  286.             else if (ch == DT_ERR)
  287.                 break;
  288.         }
  289.  
  290.         /* check for timeout */
  291.         if (ch == DT_TIME) {
  292.             bm_info(IO, ch);
  293.             md_put(IO, NAK);
  294.             continue;
  295.         }
  296.         if (ch == DT_ERR) {
  297.             bm_info(IO, ch);
  298.             dlabort(IO);
  299.             md_put(IO, CAN);
  300.             md_put(IO, CAN);
  301.             return (DT_ERR);
  302.         }
  303.         /* check the block number */
  304.         if (IO->xpr_data->packet[1] != (~IO->xpr_data->packet[2] & 0xFF)) {
  305.             bm_info(IO, DT_ERR);
  306.             md_put(IO, NAK);
  307.             continue;
  308.         }
  309.         /* check the block check code */
  310.         if (IO->xpr_data->crcmode) {    /* CRC */
  311.             IO->xpr_data->chksum = (IO->xpr_data->buffer[IO->xpr_data->msglength] << 8) | IO->xpr_data->buffer[IO->xpr_data->msglength + 1];
  312.             if (IO->xpr_data->chksum != crc_compute(IO->xpr_data->buffer, IO->xpr_data->msglength)) {
  313.                 bm_info(IO, DT_ERR);
  314.                 md_put(IO, NAK);
  315.                 continue;
  316.             }
  317.         } else {    /* checksum */
  318.             IO->xpr_data->chksum = IO->xpr_data->buffer[IO->xpr_data->msglength];
  319.             if (IO->xpr_data->chksum != chk_compute(IO->xpr_data->buffer, IO->xpr_data->msglength)) {
  320.                 bm_info(IO, DT_ERR);
  321.                 md_put(IO, NAK);
  322.                 continue;
  323.             }
  324.         }
  325.  
  326.         /* check the block number */
  327.         if (IO->xpr_data->packet[1] == (IO->xpr_data->blknum & 0xFF)) {
  328.             md_put(IO, ACK);
  329.             return (DT_OK);
  330.         } else if (IO->xpr_data->packet[1] != ((IO->xpr_data->blknum - 1) & 0xFF)) {
  331.             bm_info(IO, DT_ERR);
  332.             dlabort(IO);
  333.             md_put(IO, CAN);
  334.             md_put(IO, CAN);
  335.             return (DT_ERR);
  336.         }
  337.         /* send a ack */
  338.         md_put(IO, ACK);
  339.     }
  340.  
  341.     /* return failure */
  342.     return (DT_ERR);
  343. }
  344.  
  345. /* msgget - get a message data character */
  346. static int msgget(struct XPR_IO * IO)
  347. {
  348.     int sts;
  349.  
  350.     if (IO->xpr_data->bufptr == IO->xpr_data->msglength) {
  351.         if ((sts = mdrcv(IO)) != DT_OK)
  352.             return (sts);
  353.         bm_info(IO, 0);
  354.         ++IO->xpr_data->blknum;
  355.         IO->xpr_data->bufptr = 0;
  356.     }
  357.     return (IO->xpr_data->buffer[IO->xpr_data->bufptr++]);
  358. }
  359.  
  360. /* dl_snd - send data across the link */
  361. int dl_snd(struct XPR_IO * IO, int (*getch) (struct XPR_IO * IO))
  362. {
  363.     int ch, retries;
  364.  
  365.     IO->xpr_data->abort = 0;
  366.  
  367.     /* setup message length */
  368.     if (IO->xpr_data->big) {
  369.         IO->xpr_data->msgstart = STX;
  370.         IO->xpr_data->msglength = LMSGLEN;
  371.     } else {
  372.         IO->xpr_data->msgstart = SOH;
  373.         IO->xpr_data->msglength = SMSGLEN;
  374.     }
  375.  
  376.     /* initialize */
  377.     IO->xpr_data->blknum = 1;    /* start a block number 1 */
  378.     IO->xpr_data->bufptr = 0;    /* start with an empty buffer */
  379.  
  380.     /* wait for the initial NAK (or CRC) */
  381.     for (retries = 0; retries < RETRY; retries++)
  382.         if ((ch = md_get(IO, XTIME)) == NAK) {    /* start of checksum
  383.                              * transfer */
  384.             IO->xpr_data->crcmode = FALSE;
  385.             break;
  386.         } else if (IO->xpr_data->crc_conf && ch == CRC) {    /* start of CRC transfer */
  387.             IO->xpr_data->crcmode = TRUE;
  388.             break;
  389.         } else if (ch == DT_ERR) {
  390.             bm_info(IO, DT_ERR);
  391.             dlabort(IO);
  392.             return (FALSE);
  393.         } else if (ch == DT_TIME) {
  394.             bm_info(IO, DT_TIME);
  395.             dlabort(IO);
  396.             return (FALSE);
  397.         } else
  398.             dlabort(IO);
  399.  
  400.     /* check for failure */
  401.     if (retries >= RETRY)
  402.         return (FALSE);
  403.  
  404.     /* send each byte */
  405.     while ((ch = (*getch) (IO)) != EOF)
  406.         if (msgput(IO, ch) == DT_ERR)
  407.             return (FALSE);
  408.  
  409.     /* flush partial buffer */
  410.     if (IO->xpr_data->bufptr > 0)
  411.         while (IO->xpr_data->bufptr > 0)
  412.             if (msgput(IO, 0) == DT_ERR)
  413.                 return (FALSE);
  414.  
  415.     /* send EOT and wait for ACK */
  416.     for (retries = 0; retries < RETRY; retries++) {
  417.         md_put(IO, EOT);
  418.         if (md_get(IO, LTIME) == ACK)
  419.             return (TRUE);
  420.     }
  421.  
  422.     /* return failure */
  423.     return (FALSE);
  424. }
  425.  
  426. /* dl_rcv - receive data across the link */
  427. int dl_rcv(struct XPR_IO * IO, void (*putch) (struct XPR_IO * IO, int ch))
  428. {
  429.     int ch;
  430.  
  431.     /* initialize */
  432.     IO->xpr_data->abort = 0;
  433.     IO->xpr_data->blknum = 1;
  434.     IO->xpr_data->bufptr = IO->xpr_data->msglength = SMSGLEN;
  435.  
  436.     /* send the initial NAK (or CRC) */
  437.     IO->xpr_data->nak = (IO->xpr_data->crc_conf ? CRC : NAK);
  438.     IO->xpr_data->crcmode = IO->xpr_data->crc_conf;
  439.     md_put(IO, IO->xpr_data->nak);
  440.  
  441.     /* receive each byte */
  442.     while ((ch = msgget(IO)) != DT_EOF && ch != DT_ERR)
  443.         (*putch) (IO, ch);
  444.  
  445.     /* return with status */
  446.     return (ch == DT_EOF);
  447. }
  448.  
  449. void bm_infoinit(struct XPR_IO * IO, int send, long size)
  450. {
  451.     long (*xupdate) ();
  452.     struct XPR_UPDATE xpru;
  453.     char buff[20];
  454.  
  455.     IO->xpr_data->numerrs = 0L;
  456.     IO->xpr_data->numtime = 0L;
  457.  
  458.     if (send)
  459.         strcpy(buff, "Send    ");
  460.     else
  461.         strcpy(buff, "Receive ");
  462.     if (IO->xpr_data->ascii)
  463.         strcat(buff, "Text  ");
  464.     else
  465.         strcat(buff, "Binary");
  466.  
  467.     xpru.xpru_updatemask = XPRU_MSG | XPRU_FILENAME |
  468.         XPRU_BLOCKSIZE | XPRU_BLOCKCHECK | XPRU_BYTES |
  469.         XPRU_BLOCKS | XPRU_TIMEOUTS | XPRU_ERRORS;
  470.     IO->xpr_data->filsiz = size;
  471.     if (size)
  472.         xpru.xpru_updatemask |= XPRU_FILESIZE;
  473.  
  474.     xpru.xpru_filename = IO->xpr_filename;
  475.     xpru.xpru_filesize = size;
  476.     xpru.xpru_msg = buff;
  477.     xpru.xpru_blocks = 0L;
  478.     xpru.xpru_errors = 0L;
  479.     xpru.xpru_timeouts = 0L;
  480.     xpru.xpru_blocksize = IO->xpr_data->big ? 1024L : 128L;
  481.     xpru.xpru_blockcheck = IO->xpr_data->crc_conf ? blkchk[1] : blkchk[0];
  482.     xpru.xpru_bytes = 0L;
  483.  
  484.     if ((xupdate = IO->xpr_update) != NULL)
  485.         calla(xupdate, &xpru);
  486.  
  487.     CurrentTime(&IO->xpr_data->startsecs, &IO->xpr_data->startmics);
  488.  
  489.     return;
  490. }
  491.